require 'parser/SymTable.rb'
require 'parser/SymVariable.rb'

# = Class ASTBlock
# Inherits from ASTStatement. Represents the implementation of an AST especifically designed
# for instruction blocks
# == Attributes inherited from ASTStatement
# node, children
# == Methods inherited from ASTStatement
# check(), run(), to_s_children
class ASTBlock < ASTStatement
  # AST representing the declaration segment of the block
  attr_reader :decl 
  # AST representing the instruction segment of the block
  attr_reader :inst
  # Symbol Table associated with this instruction block
  attr_reader :local_sym_table
  # Value of the block after it is run
  attr_reader :value
  # Symbol containing the returned value of the block
  attr_reader :returned
  
  # Constructor of the class
  # === Parameters
  # * decl: AST representing the declaration segment of the block
  # * inst: AST representing the instruction segment of the block
  def initialize(decl, children)
    @decl = decl
    @local_sym_table = SymTable.new
    for vars in @decl.children
      for var in vars.names
        if nil != @local_sym_table.find(var.value)
          raise "La variable #{var} está siendo redeclarada"
        end
        @local_sym_table.insert(SymVariable.new(var.value, vars.type))
      end
    end if @decl != nil
    @children = children
    #for c in @children
    #  puts "hijo #{c.class.name} de bloque"
    #end
  end

  # Method to run the instruction block
  # === Parameters
  # * parent_sym_table: Symbol table passed by the parent AST
  # * func_table: Function symbol table passed by the parent AST
  # === Return value
  # nil if executed with success or an error message
  def run parent_sym_table, func_table
    @returned = nil
    sym_table = SymTable.new
    sym_table.merge_table parent_sym_table
    sym_table.merge_table @local_sym_table
    for inst in @children
      msg = inst.run sym_table, func_table
      if nil != msg
        return msg
      end
      if nil != inst.returned
        @returned = inst.returned
        return nil
      end
    end
    nil
  end

  # Method to check the static correctitude of the statement
  # === Parameters
  # * parent_sym_table: Symbol table passed by the parent AST
  # * func_table: Function symbol table passed by the pare
  # * func_type: Type of valid return value
  # === Return value
  # nil if executed with success or an error message
  def check parent_sym_table, func_table, func_type
    sym_table = SymTable.new
    sym_table.merge_table parent_sym_table
    sym_table.merge_table @local_sym_table
    for inst in @children
      msg = inst.check sym_table, func_table, func_type
      if nil != msg
        return msg
      end
    end if @children != nil
    nil
  end

  # Returns the closest wrong token to the place were an error is generated
  def error_tk
    for i in @children
      tk = i.error_tk
      if nil != tk
        return tk
      end
    end if nil != @children
    nil
  end

  # Creates a 'String' representation of the AST with 'i' identation spaces
  # === Parameters
  # * i: Identation with which the AST should be printed with
  def to_s(i)
    im = i + @@c
    ts = @local_sym_table.to_s(i) == "" ? "" : "\n#{im}Tabla de símbolos:" + @local_sym_table.to_s(im + @@c)
    "(Bloque de código#{ts}" + to_s_children(im) + "\n#{i})"
  end
end